#include <iostream>
#include <vector>
#include <easyx.h>
#include <windows.h>
#include <ctime>
#include <fstream>

int highScore = 0;
void loadHighScore() {
    std::ifstream fin("highscore.txt");
    if (fin >> highScore) {}
    else {
        highScore = 0;
    }
    fin.close();
}

void saveHighScore() {
    std::ofstream fout("highscore.txt");
    fout << highScore;
    fout.close();
}

class block {
public:
    int m_x, m_y;
    COLORREF m_color;
    block() : block(0, 0) {}
    block(int x, int y) : m_x(x), m_y(y), m_color(RED) {}
    virtual void draw() {
        setfillcolor(m_color);
        fillrectangle(m_x, m_y, m_x + 10, m_y + 10);
    }
};

class food : public block {
public:
    food() : block(0, 0) {
        m_x = rand() % 50 * 10;
        m_y = rand() % 50 * 10;
        m_color = GREEN;
    }
    void draw() override {
        setfillcolor(m_color);
        solidellipse(m_x, m_y, m_x + 10, m_y + 10);
    }
};

class snake : public block {
public:
    std::vector<block> tsnake;
    int direction = VK_RIGHT;
    int score = 0;

    snake() : snake(0, 0) {}
    snake(int x, int y) : block(x, y) {
        tsnake.push_back(block(20, 0));
        tsnake.push_back(block(10, 0));
        tsnake.push_back(block(0, 0));
    }

    void draw() override {
        for (auto& a : tsnake) {
            setfillcolor(a.m_color);
            fillrectangle(a.m_x, a.m_y, a.m_x + 10, a.m_y + 10);
        }
    }

    void bodymove() {
        for (int i = tsnake.size() - 1; i > 0; i--) {
            tsnake[i].m_x = tsnake[i - 1].m_x;
            tsnake[i].m_y = tsnake[i - 1].m_y;
        }
        int x = 0, y = 0;
        switch (direction) {
        case VK_UP:    x = 0; y = -10; break;
        case VK_DOWN:  x = 0; y = 10;  break;
        case VK_RIGHT: x = 10; y = 0;  break;
        case VK_LEFT:  x = -10; y = 0; break;
        }
        tsnake[0].m_x += x;
        tsnake[0].m_y += y;
    }

    bool CollisionDetection(block& other) {
        if (tsnake[0].m_x == other.m_x && tsnake[0].m_y == other.m_y) {
            tsnake.push_back(tsnake.back());
            score++;
            return true;
        }
        return false;
    }

    bool BodyDetection() {
        for (size_t i = 1; i < tsnake.size(); ++i) {
            if (tsnake[0].m_x == tsnake[i].m_x && tsnake[0].m_y == tsnake[i].m_y)
                return true;
        }
        return false;
    }
};

class game {
public:
    snake ssnake;
    food ffood;
    bool state = true;

    game() { srand((unsigned)time(nullptr)); }

    void run() {
        BeginBatchDraw();
        cleardevice();
        ssnake.draw();
        ffood.draw();
        // 显示分数和最高分
        setbkmode(TRANSPARENT);
        settextcolor(WHITE);
        TCHAR scoreStr[64];
        swprintf_s(scoreStr, 64, _T("Score: %d   High Score: %d"), ssnake.score, highScore);
        outtextxy(10, 10, scoreStr);
        EndBatchDraw();
    }

    void update() {
        ssnake.bodymove();
        // 边界检测
        if (ssnake.tsnake[0].m_x < 0 || ssnake.tsnake[0].m_x >= 500 ||
            ssnake.tsnake[0].m_y < 0 || ssnake.tsnake[0].m_y >= 500) {
            state = false;
        }
        // 自身碰撞检测
        if (ssnake.BodyDetection()) {
            state = false;
        }
        if (ssnake.CollisionDetection(ffood)) {
            ffood.m_x = rand() % 50 * 10;
            ffood.m_y = rand() % 50 * 10;
        }
    }

    void change(ExMessage& exg) {
        if (exg.message == WM_KEYDOWN) {
            int newdir = ssnake.direction;
            if (exg.vkcode == VK_UP && ssnake.direction != VK_DOWN) newdir = VK_UP;
            if (exg.vkcode == VK_DOWN && ssnake.direction != VK_UP) newdir = VK_DOWN;
            if (exg.vkcode == VK_LEFT && ssnake.direction != VK_RIGHT) newdir = VK_LEFT;
            if (exg.vkcode == VK_RIGHT && ssnake.direction != VK_LEFT) newdir = VK_RIGHT;
            ssnake.direction = newdir;
        }
    }
};

int main() {
    int det = 0;
    std::cout << "欢迎来到贪吃蛇的世界，注意不要让你的蛇头碰到墙壁和自己的身体，吃下最多的食物，登顶世界最高峰" << std::endl << "按1开始游戏，按2查看最高分，按3退出游戏" << std::endl;
        while (det==0) {     
            int where=0;                  
            std::cin >> where;
            switch (where)
            {
            case 1:
                initgraph(500, 500, EX_SHOWCONSOLE);
                loadHighScore();
                while (true)  {
                    game gamefine;
                    while (gamefine.state) {
                        ExMessage msg = { 0 };
                        while (peekmessage(&msg, EX_KEY)) {
                            gamefine.change(msg);
                        }
                        gamefine.update();
                        gamefine.run();
                        Sleep(100);
                    }
                    if (gamefine.ssnake.score > highScore) {
                        highScore = gamefine.ssnake.score;
                        saveHighScore();
                        int ret = MessageBoxA(NULL, "创纪录啦！最高分被你刷行啦\n，点击“重试”继续，点击“取消”退出。", "Snake", MB_RETRYCANCEL | MB_ICONQUESTION);
                        if (ret == IDCANCEL) break;
                    }
                    else {
                        char msg[128];
                        sprintf_s(msg, "继续努力吧，你离最高分还差 %d分\n，点击“重试”继续，点击“取消”退出。", highScore - gamefine.ssnake.score);
                        int ret = MessageBoxA(NULL, msg/*"继续努力吧，你离最高分还差\n，点击“重试”继续，点击“取消”退出。"*/, "Snake", MB_RETRYCANCEL | MB_ICONQUESTION);
                        if (ret == IDCANCEL) break;
                    }
                }                                                                                            
                
                break;
            case 2:
                loadHighScore();
                std::cout << highScore<<std::endl;
                break;
            case 3:
                det = 1;
                break;

            }
        }closegraph();
    return 0;
}